﻿#region License

// Created by John Batte on 04/04/2012 at 10:47 AM.
// Last code cleanup: 04/04/2012 at 10:47 AM.
// 
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

#endregion

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;

namespace BatteCode.Google.Wiki
{
	/// <summary>
	/// Provides xml comment extensions.
	/// </summary>
	public static class CommentExtensions
	{
		private static readonly IDictionary<MemberTypes, Func<MemberInfo, string>> _nameFactories
			= new Dictionary<MemberTypes, Func<MemberInfo, string>>
			{
				{ MemberTypes.NestedType, m => GetCommentName(m as Type) },
				{ MemberTypes.TypeInfo, m => GetCommentName(m as Type) },
				{ MemberTypes.Method, m => GetCommentName(m as MethodInfo) },
				{ MemberTypes.Property, m => GetCommentName(m as PropertyInfo) }
			};

		/// <summary>
		/// Gets the comments for the specified member.
		/// </summary>
		/// <param name="xml">The XML.</param>
		/// <param name="member">The member.</param>
		/// <returns></returns>
		public static XElement GetCommentsForMember(this XElement xml, MemberInfo member)
		{
			string commentName = member.GetCommentName();
			return string.IsNullOrEmpty(commentName)
			       	? null
			       	: xml.Descendants("member").FirstOrDefault(x => x.Attribute("name").Value.StartsWith(commentName));
		}

		/// <summary>
		/// Gets the comment name of the member.
		/// </summary>
		/// <param name="member">The member.</param>
		/// <returns></returns>
		public static string GetCommentName(this MemberInfo member)
		{
			var nameFactory = _nameFactories.ContainsKey(member.MemberType) ? _nameFactories[member.MemberType] : null;
			return nameFactory == null ? null : nameFactory(member);
		}

		private static string GetFullTypeName(Type type)
		{
			return type.IsNested ? string.Format("{0}.{1}", GetFullTypeName(type.DeclaringType), type.Name) : type.FullName;
		}

		private static string GetCommentName(Type type)
		{
			return string.Format("T:{0}", GetFullTypeName(type));
		}

		private static string GetCommentName(MethodInfo method)
		{
			return string.Format("M:{0}.{1}", GetFullTypeName(method.DeclaringType), method.Name);
		}

		private static string GetCommentName(PropertyInfo property)
		{
			return string.Format("P:{0}.{1}", GetFullTypeName(property.DeclaringType), property.Name);
		}
	}
}